import tkinter as tk
from threading import Thread


# *****************
# 可滚动框架类
# *****************
class ScrollFrame(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)  # 创建一个框架 (self)

        self.canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0,)  # 将画布放在 self 上
        self.viewPort = tk.Frame(self.canvas,)  # 在画布上放置一个框架，这个框架将容纳子部件
        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview, width=12,)  # 在 self 上放置滚动条
        self.canvas.configure(yscrollcommand=self.vsb.set)  # 将滚动条操作附加到画布滚动

        self.vsb.pack(side="right", fill="y")  # 将滚动条打包到自己的右边
        self.canvas.pack(side="left", fill="both", expand=True)  # 将画布打包到自己的左边，然后扩展到FIL
        self.canvas_window = self.canvas.create_window((4, 4), window=self.viewPort, anchor="nw",
                                                       # 将视图端口框架添加到画布中
                                                       tags="self.viewPort")

        self.viewPort.bind("<Configure>",
                           self.onFrameConfigure)  # 每当视口框架的大小发生变化时，就绑定一个事件
        self.canvas.bind("<Configure>",
                         self.onCanvasConfigure)  # 每当视口框架的大小发生变化时，就绑定一个事件

        self.onFrameConfigure(
            None)  # 在呈现时执行初始拉伸，否则滚动区域将有一个很小的边框，直到第一次调整大小为止

    def onFrameConfigure(self, event):
        # """将滚动区域重新设置为包含内部框架"""
        self.canvas.configure(scrollregion=self.canvas.bbox(
            "all"))  # 每当框架的大小发生变化时，分别更改滚动区域

    def onCanvasConfigure(self, event):
        # """在需要时重新设置画布窗口以包含内部框架"""
        canvas_width = event.width
        self.canvas.itemconfig(self.canvas_window,
                               width=canvas_width)  # 每当画布的大小发生变化时，分别更改窗口区域


# *****************
# 自定义滚动Frame
# *****************
class MyScrollFrame(tk.Frame):
    def __init__(self, master):
        """
        :param master: 父级控件
        """
        tk.Frame.__init__(self, master)
        self.scrollFrame = ScrollFrame(self)  # 添加新的可滚动框架

        # 将一些控件添加到滚动框中，子控件被添加到视图端口(需添加到self.scrollFrame.viewPort，而不是滚动帧本身self.scrollFrame)
        # func(self.scrollFrame.viewPort)

        # 在打包滚动框时，我们打包滚动框架本身(self.scrollFrame)，而不是视图端口(self.scrollFrame.viewPort)
        self.scrollFrame.pack(side="top", fill="both", expand=True)

    def get_container(self):
        """
        :return: 返回视图端口，即可滚动容器
        """
        return self.scrollFrame.viewPort


# *****************
# 开启多线程
# *****************
class MyThread(Thread):
    """
    开启多线程，有返回值
    """
    def __init__(self, func, args=()):
        Thread.__init__(self)
        self.func = func
        self.args = args
        self.result = 'Not started'

    def run(self):
        print('线程开始！')
        self.result = 'Started'
        self.result = self.func(*self.args)
        print('线程结束！')

    def get_result(self):
        # 得到多线程函数返回
        return self.result
